//---------------------------------------------------------------------------
// NEOPOP : Emulator as in Dreamland
//
// Copyright (c) 2001-2002 by neopop_uk
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version. See also the license.txt file for
//	additional informations.
//---------------------------------------------------------------------------

/*
//---------------------------------------------------------------------------
//=========================================================================

	TLCS900h_disassemble_reg.c

//=========================================================================
//---------------------------------------------------------------------------

  History of changes:
  ===================

20 JUL 2002 - neopop_uk
=======================================
- Cleaned and tidied up for the source release

22 JUL 2002 - neopop_uk
=======================================
- Fixed disassembly of Link, it's second operand is signed.

28 JUL 2002 - neopop_uk
=======================================
- Better disassembly of MUL/MULS/DIV/DIVS - operand size is shown.
  
//---------------------------------------------------------------------------
*/

#include "../neopop.h"
#include "TLCS900h_disassemble.h"
#include "TLCS900h_registers.h"
#include "TLCS900h_interpret.h"

//=========================================================================

namespace TLCS900H
{

static void LDi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "LD %s,0x%02X", str_r, get8_dis());	break;
	case 1:	sprintf(instr, "LD %s,0x%04X", str_r, get16_dis());	break;
	case 2: sprintf(instr, "LD %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void PUSH()
{
	sprintf(instr, "PUSH %s", str_r);
}

static void POP()
{
	sprintf(instr, "POP %s", str_r);
}

static void CPL()
{
	sprintf(instr, "CPL %s", str_r);
}

static void NEG()
{
	sprintf(instr, "NEG %s", str_r);
}

static void MULi()
{
	get_rr_Name();

	switch(size)
	{
	case 0:	sprintf(instr, "MUL.b %s,0x%02X", str_r, get8_dis());	break;
	case 1: sprintf(instr, "MUL.w %s,0x%04X", str_r, get16_dis());	break;
	}
}

static void MULSi()
{
	get_rr_Name();

	switch(size)
	{
	case 0:	sprintf(instr, "MULS.b %s,0x%02X", str_r, get8_dis());	break;
	case 1: sprintf(instr, "MULS.w %s,0x%04X", str_r, get16_dis());	break;
	}
}

static void DIVi()
{
	get_rr_Name();

	switch(size)
	{
	case 0:	sprintf(instr, "DIV.b %s,0x%02X", str_r, get8_dis());	break;
	case 1: sprintf(instr, "DIV.w %s,0x%04X", str_r, get16_dis());	break;
	}
}

static void DIVSi()
{
	get_rr_Name();

	switch(size)
	{
	case 0:	sprintf(instr, "DIVS.b %s,0x%02X", str_r, get8_dis());	break;
	case 1: sprintf(instr, "DIVS.w %s,0x%04X", str_r, get16_dis());	break;
	}
}

static void LINK()
{
	sprintf(instr, "LINK %s, %d", str_r, (int16)get16_dis());
}

static void UNLK()
{
	sprintf(instr, "UNLK %s", str_r);
}

static void BS1F()
{
	sprintf(instr, "BS1F A,%s", str_r);
}

static void BS1B()
{
	sprintf(instr, "BS1B A,%s", str_r);
}

static void DAA()
{
	sprintf(instr, "DAA %s", str_r);
}

static void EXTZ()
{
	sprintf(instr, "EXTZ %s", str_r);
}

static void EXTS()
{
	sprintf(instr, "EXTS %s", str_r);
}

static void PAA()
{
	sprintf(instr, "PAA %s", str_r);
}

static void MIRR()
{
	sprintf(instr, "MIRR %s", str_r);
}

static void MULA()
{
	sprintf(instr, "MULA %s", str_r);
}

static void DJNZ()
{
	sprintf(instr, "DJNZ %s,0x%06X", str_r, (int8)get8_dis() + pc);
}

static void ANDCFi()
{
	sprintf(instr, "ANDCF %d,%s", get8_dis() & 0xF, str_r);
}

static void ORCFi()
{
	sprintf(instr, "ORCF %d,%s", get8_dis() & 0xF, str_r);
}

static void XORCFi()
{
	sprintf(instr, "XORCF %d,%s", get8_dis() & 0xF, str_r);
}

static void LDCFi()
{
	sprintf(instr, "LDCF %d,%s", get8_dis() & 0xF, str_r);
}

static void STCFi()
{
	sprintf(instr, "STCF %d,%s", get8_dis() & 0xF, str_r);
}

static void ANDCFA()
{
	sprintf(instr, "ANDCF A,%s", str_r);
}

static void ORCFA()
{
	sprintf(instr, "ORCF A,%s", str_r);
}

static void XORCFA()
{
	sprintf(instr, "XORCF A,%s", str_r);
}

static void LDCFA()
{
	sprintf(instr, "LDCF A,%s", str_r);
}

static void STCFA()
{
	sprintf(instr, "STCF A,%s", str_r);
}

static void LDCcrr()
{
	uint8 cr = get8_dis();
	sprintf(instr, "LDC %s,%s", crName[size][cr >> size], str_r);
}

static void LDCrcr()
{
	uint8 cr = get8_dis();
	sprintf(instr, "LDC %s,%s", str_r, crName[size][cr >> size]);
}

static void RES()
{
	sprintf(instr, "RES %d,%s", get8_dis() & 0xF, str_r);
}

static void SET()
{
	sprintf(instr, "SET %d,%s", get8_dis() & 0xF, str_r);
}

static void CHG()
{
	sprintf(instr, "CHG %d,%s", get8_dis() & 0xF, str_r);
}

static void BIT()
{
	sprintf(instr, "BIT %d,%s", get8_dis() & 0xF, str_r);
}

static void TSET()
{
	sprintf(instr, "TSET %d,%s", get8_dis() & 0xF, str_r);
}

static void MINC1()
{
	sprintf(instr, "MINC1 %d,%s", get16_dis()+1, str_r);
}

static void MINC2()
{
	sprintf(instr, "MINC2 %d,%s", get16_dis()+2, str_r);
}

static void MINC4()
{
	sprintf(instr, "MINC4 %d,%s", get16_dis()+4, str_r);
}

static void MDEC1()
{
	sprintf(instr, "MDEC1 %d,%s", get16_dis()+1, str_r);
}

static void MDEC2()
{
	sprintf(instr, "MDEC2 %d,%s", get16_dis()+2, str_r);
}

static void MDEC4()
{
	sprintf(instr, "MDEC4 %d,%s", get16_dis()+4, str_r);
}

static void MUL()
{
	get_RR_Name();
	switch(size)
	{
	case 0:	sprintf(instr, "MUL.b %s,%s", str_R, str_r);	break;
	case 1: sprintf(instr, "MUL.w %s,%s", str_R, str_r);	break;
	}
}

static void MULS()
{
	get_RR_Name();
	switch(size)
	{
	case 0:	sprintf(instr, "MULS.b %s,%s", str_R, str_r);	break;
	case 1: sprintf(instr, "MULS.w %s,%s", str_R, str_r);	break;
	}
}

static void DIV()
{
	get_RR_Name();
	switch(size)
	{
	case 0:	sprintf(instr, "DIV.b %s,%s", str_R, str_r);	break;
	case 1: sprintf(instr, "DIV.w %s,%s", str_R, str_r);	break;
	}
}

static void DIVS()
{
	get_RR_Name();
	switch(size)
	{
	case 0:	sprintf(instr, "DIVS.b %s,%s", str_R, str_r);	break;
	case 1: sprintf(instr, "DIVS.w %s,%s", str_R, str_r);	break;
	}
}

static void INC()
{
	uint8 val = (second & 7);
	if (val == 0)
		val = 8;

	sprintf(instr, "INC %d,%s", val, str_r);
}

static void DEC()
{
	uint8 val = (second & 7);
	if (val == 0)
		val = 8;

	sprintf(instr, "DEC %d,%s", val, str_r);
}

static void SCC()
{
	sprintf(instr, "SCC %s,%s", ccName[second & 0xF], str_r);
}

static void ADD()
{
	sprintf(instr, "ADD %s,%s", str_R, str_r);
}

static void LDRr()
{
	sprintf(instr, "LD %s,%s", str_R, str_r);
}

static void LDrR()
{
	sprintf(instr, "LD %s,%s", str_r, str_R);
}

static void ADC()
{
	sprintf(instr, "ADC %s,%s", str_R, str_r);
}

static void SUB()
{
	sprintf(instr, "SUB %s,%s", str_R, str_r);
}

static void SBC()
{
	sprintf(instr, "SBC %s,%s", str_R, str_r);
}

static void LDr3()
{
	sprintf(instr, "LD %s,%d", str_r, second & 7);
}

static void EX()
{
	sprintf(instr, "EX %s,%s", str_R, str_r);
}

static void AND()
{
	sprintf(instr, "AND %s,%s", str_R, str_r);
}

static void ADDi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "ADD %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "ADD %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "ADD %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void ADCi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "ADC %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "ADC %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "ADC %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void SUBi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "SUB %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "SUB %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "SUB %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void SBCi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "SBC %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "SBC %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "SBC %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void ANDi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "AND %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "AND %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "AND %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void XORi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "XOR %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "XOR %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "XOR %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void ORi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "OR %s,0x%02X", str_r, get8_dis());		break;
	case 1:	sprintf(instr, "OR %s,0x%04X", str_r, get16_dis());		break;
	case 2:	sprintf(instr, "OR %s,0x%08X", str_r, get32_dis());		break;
	}
}

static void CPi()
{
	switch(size)
	{
	case 0:	sprintf(instr, "CP %s,0x%02X", str_r, get8_dis());	break;
	case 1:	sprintf(instr, "CP %s,0x%04X", str_r, get16_dis());	break;
	case 2:	sprintf(instr, "CP %s,0x%08X", str_r, get32_dis());	break;
	}
}

static void XOR()
{
	sprintf(instr, "XOR %s,%s", str_R, str_r);
}

static void CPr3()
{
	sprintf(instr,"CP %s,%d", str_r, second&7);
}

static void OR()
{
	sprintf(instr, "OR %s,%s", str_R, str_r);
}

static void RLCi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "RLC %d,%s", val, str_r);
}

static void RRCi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "RRC %d,%s", val, str_r);
}

static void RLi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "RL %d,%s", val, str_r);
}

static void RRi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "RR %d,%s", val, str_r);
}

static void SLAi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "SLA %d,%s", val, str_r);
}

static void SRAi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "SRA %d,%s", val, str_r);
}

static void SLLi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "SLL %d,%s", val, str_r);
}

static void SRLi()
{
	uint8 val = get8_dis() & 0xF;
	if (val == 0) val = 16;
	sprintf(instr, "SRL %d,%s", val, str_r);
}

static void CP()
{
	sprintf(instr, "CP %s,%s", str_R, str_r);
}

static void RLCA()
{
	sprintf(instr, "RLC A,%s", str_r);
}

static void RRCA()
{
	sprintf(instr, "RRC A,%s", str_r);
}

static void RLA()
{
	sprintf(instr, "RL A,%s", str_r);
}

static void RRA()
{
	sprintf(instr, "RR A,%s", str_r);
}

static void SLAA()
{
	sprintf(instr, "SLA A,%s", str_r);
}

static void SRAA()
{
	sprintf(instr, "SRA A,%s", str_r);
}

static void SLLA()
{
	sprintf(instr, "SLL A,%s", str_r);
}

static void SRLA()
{
	sprintf(instr, "SRL A,%s", str_r);
}

//=========================================================================

//Secondary (REG) Instruction decode
static void (*decode[256])() = 
{
/*0*/	0,		0,		0,		LDi,	PUSH,	POP,	CPL,	NEG,
		MULi,	MULSi,	DIVi,	DIVSi,	LINK,	UNLK,	BS1F,	BS1B,
/*1*/	DAA,	0,		EXTZ,	EXTS,	PAA,	0,		MIRR,	0,
		0,		MULA,	0,		0,		DJNZ,	0,		0,		0,
/*2*/	ANDCFi,	ORCFi,	XORCFi,	LDCFi,	STCFi,	0,		0,		0,
		ANDCFA,	ORCFA,	XORCFA,	LDCFA,	STCFA,	0,		LDCcrr,	LDCrcr,
/*3*/	RES,	SET,	CHG,	BIT,	TSET,	0,		0,		0,
		MINC1,	MINC2,	MINC4,	0,		MDEC1,	MDEC2,	MDEC4,	0,
/*4*/	MUL,	MUL,	MUL,	MUL,	MUL,	MUL,	MUL,	MUL,
		MULS,	MULS,	MULS,	MULS,	MULS,	MULS,	MULS,	MULS,
/*5*/	DIV,	DIV,	DIV,	DIV,	DIV,	DIV,	DIV,	DIV,
		DIVS,	DIVS,	DIVS,	DIVS,	DIVS,	DIVS,	DIVS,	DIVS,
/*6*/	INC,	INC,	INC,	INC,	INC,	INC,	INC,	INC,
		DEC,	DEC,	DEC,	DEC,	DEC,	DEC,	DEC,	DEC,
/*7*/	SCC,	SCC,	SCC,	SCC,	SCC,	SCC,	SCC,	SCC,
		SCC,	SCC,	SCC,	SCC,	SCC,	SCC,	SCC,	SCC,
/*8*/	ADD,	ADD,	ADD,	ADD,	ADD,	ADD,	ADD,	ADD,
		LDRr,	LDRr,	LDRr,	LDRr,	LDRr,	LDRr,	LDRr,	LDRr,
/*9*/	ADC,	ADC,	ADC,	ADC,	ADC,	ADC,	ADC,	ADC,
		LDrR,	LDrR,	LDrR,	LDrR,	LDrR,	LDrR,	LDrR,	LDrR,
/*A*/	SUB,	SUB,	SUB,	SUB,	SUB,	SUB,	SUB,	SUB,
		LDr3,	LDr3,	LDr3,	LDr3,	LDr3,	LDr3,	LDr3,	LDr3,
/*B*/	SBC,	SBC,	SBC,	SBC,	SBC,	SBC,	SBC,	SBC,
		EX,		EX,		EX,		EX,		EX,		EX,		EX,		EX,
/*C*/	AND,	AND,	AND,	AND,	AND,	AND,	AND,	AND,
		ADDi,	ADCi,	SUBi,	SBCi,	ANDi,	XORi,	ORi,	CPi,
/*D*/	XOR,	XOR,	XOR,	XOR,	XOR,	XOR,	XOR,	XOR,
		CPr3,	CPr3,	CPr3,	CPr3,	CPr3,	CPr3,	CPr3,	CPr3,
/*E*/	OR,		OR,		OR,		OR,		OR,		OR,		OR,		OR,
		RLCi,	RRCi,	RLi,	RRi,	SLAi,	SRAi,	SLLi,	SRLi,
/*F*/	CP,		CP,		CP,		CP,		CP,		CP,		CP,		CP,
		RLCA,	RRCA,	RLA,	RRA,	SLAA,	SRAA,	SLLA,	SRLA
};

//=============================================================================

void TLCS900h_disassemble_reg(int opsize)
{
	second = get8_dis();	//Get the second opcode
	size = opsize;

	//Prepare 'Big R'
	sprintf(str_R, "%s", gprName[second & 7][size]);

	//Prepare 'little r'
	if (brCode)
		sprintf(str_r, "%s", extra);
	else
		sprintf(str_r, "%s", gprName[first & 7][opsize]); 

	if (decode[second])
		(*decode[second])();
	else
		sprintf(instr, "unknown reg instr. %02X", second);
}
};
